package pl.jtb.ctl.tabory.ui.boe.ui.te;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.Section;

import pl.jtb.ctl.tabory.dao.api.services.ICompositionService;
import pl.jtb.ctl.tabory.dao.api.services.IStationService;
import pl.jtb.ctl.tabory.dao.api.services.ITripService;
import pl.jtb.ctl.tabory.dao.data.vo.CompositionVO;
import pl.jtb.ctl.tabory.dao.data.vo.StationVO;
import pl.jtb.ctl.tabory.dao.data.vo.TripVO;
import pl.jtb.ctl.tabory.dao.data.vo.VagonVO;
import pl.jtb.ctl.tabory.dao.impl.mybatis.servicemanager.ServiceManager;
import pl.jtb.ctl.tabory.ui.boe.osgi.Activator;
import pl.jtb.ctl.tabory.ui.boe.selection.CompositionSelection;
import pl.jtb.ctl.tabory.ui.boe.selection.TripSelection;
import pl.jtb.ctl.tabory.ui.boe.selection.VagonSelection;
import pl.jtb.ctl.tabory.ui.boe.ui.ce.CompositionMasterSectionPart;
import pl.jtb.ctl.tabory.ui.editors.AbstractEditorPart;
import pl.jtb.ctl.tabory.ui.editors.EditorStateSL;
import pl.jtb.ctl.tabory.ui.selection.ISelectionListener;

public class TripEditor extends AbstractEditorPart<TripSelection> {

    public static final String ID = "pl.jtb.ctl.tabory.ui.boe.ui.te.TripEditor";
    private final static Logger logger = Logger.getLogger(TripEditor.class);

    protected Action editorNewAction;
    protected Action editorEditAction;
    protected Action editorDeleteAction;
    private CompositionMasterSectionPart compositionSection;
    private TripSection tripSection;

    private CompositionSelection compositionSelection;
    private VagonSelection vagonSelection;
    private TripVagonSection tripVagonSection;

    public TripEditor() throws Exception {
        super();
    }

    @Override
    protected void createActions() {
        super.createActions();
        editorNewAction = new Action(Activator.getMessage("trip.editor.toolbar.new")) {
            @Override
            public void run() {
                logger.debug("Run menu action: new element.");
                BusyIndicator.showWhile(form.getDisplay(), new Runnable() {
                    @Override
                    public void run() {
                        try {
                            doNew();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                            openErrorDialog(e);
                        }
                    }
                });
            }
        };
        editorEditAction = new Action(Activator.getMessage("trip.editor.toolbar.edit")) {
            @Override
            public void run() {
                logger.debug("Run menu action: edit element.");
                BusyIndicator.showWhile(form.getDisplay(), new Runnable() {
                    @Override
                    public void run() {
                        try {
                            doEdit();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                            openErrorDialog(e);
                        }
                    }
                });
            }
        };
        editorDeleteAction = new Action(Activator.getMessage("trip.editor.toolbar.delete")) {
            @Override
            public void run() {
                logger.debug("Run menu action: delete element.");
                BusyIndicator.showWhile(form.getDisplay(), new Runnable() {
                    @Override
                    public void run() {
                        try {
                            doDelete();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                            openErrorDialog(e);
                        }
                    }
                });
            }
        };
        editorNewAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_NEW_WIZARD));
        editorEditAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
        editorDeleteAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_DELETE));
    }

    @Override
    public void createPartControl(Composite parent) {
        super.createPartControl(parent);
        form.getToolBarManager().removeAll();
        form.getToolBarManager().add(editorNewAction);
        form.getToolBarManager().add(editorEditAction);
        form.getToolBarManager().add(editorDeleteAction);
        form.getToolBarManager().update(true);
    }

    private void doNew() throws Exception {
        TripDialog dialog = new TripDialog(getSite().getShell(), selection.getMapDistances(), selection.getListComposition(), selection.getListStation(), null, compositionSelection.getSelectedComposition());
        int open = dialog.open();
        if (open == Window.OK) {
            TripVO value = dialog.getValue();
            ServiceManager.getInstance().getTripService().saveUpdateTrip(value);
            compositionSection.setSelection(compositionSelection);
            selection.setSelectedTrip(null);
            tripSection.setSelection(selection);
            updateSelection();
        }
    }

    private void doEdit() throws Exception {
        TripDialog dialog = new TripDialog(getSite().getShell(), selection.getMapDistances(), selection.getListComposition(), selection.getListStation(), selection.getSelectedTrip(), compositionSelection.getSelectedComposition());
        int open = dialog.open();
        if (open == Window.OK) {
            TripVO value = dialog.getValue();
            ServiceManager.getInstance().getTripService().saveUpdateTrip(value);
            compositionSection.setSelection(compositionSelection);
            selection.setSelectedTrip(null);
            tripSection.setSelection(selection);
            updateSelection();
        }
    }

    private void doDelete() throws Exception {
        MessageBox messageBox = new MessageBox(getSite().getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO);
        messageBox.setMessage(Activator.getMessage("trip.editor.dialog.delete.message"));
        messageBox.setText(Activator.getMessage("trip.editor.dialog.delete.title"));
        int result = messageBox.open();
        if (result == SWT.YES) {
            ServiceManager.getInstance().getTripService().deleteTrip(selection.getSelectedTrip());
            compositionSection.setSelection(compositionSelection);
            selection.setSelectedTrip(null);
            tripSection.setSelection(selection);
        }
        updateSelection();
    }

    @Override
    protected void initGui(Composite parent) {
        GridLayoutFactory.fillDefaults().numColumns(2).margins(5, 5).applyTo(form.getBody());

        Composite container = formToolkit.createComposite(form.getBody(), SWT.NONE);
        GridLayoutFactory.fillDefaults().numColumns(2).applyTo(container);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(container);

        SashForm leftComposite = new SashForm(container, SWT.VERTICAL);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(leftComposite);
        formToolkit.paintBordersFor(leftComposite);
        formToolkit.adapt(leftComposite);

        compositionSection = new CompositionMasterSectionPart(leftComposite, formToolkit, Section.TITLE_BAR, Activator.getMessage("trip.editor.compositionsection.title"), false, true);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, true).applyTo(compositionSection.getSection());

        SashForm rightComposite = new SashForm(container, SWT.VERTICAL);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(rightComposite);
        formToolkit.paintBordersFor(rightComposite);
        formToolkit.adapt(rightComposite);

        tripSection = new TripSection(rightComposite, formToolkit, Section.TITLE_BAR, Activator.getMessage("trip.editor.tripsection.title"));
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tripSection.getSection());

        tripVagonSection = new TripVagonSection(rightComposite, formToolkit, Section.TITLE_BAR);
        GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo(tripVagonSection.getSection());
    }

    @Override
    protected void postInitGui(Composite parent) {
        updateButtons();
        compositionSection.addSelectionListener(new ISelectionListener<CompositionSelection>() {
            @Override
            public void selectionChanged(final CompositionSelection sel) {
                BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
                    @Override
                    public void run() {
                        CompositionVO selectedComposition = sel.getSelectedComposition();
                        if (selectedComposition != null) {
                            List<TripVO> listTripsForComposition;
                            try {
                                listTripsForComposition = ServiceManager.getInstance().getTripService().getTripsForComposition(selectedComposition.getId());
                                compositionSelection.setSelectedComposition(selectedComposition);
                                selection.setListTrips(listTripsForComposition);
                                selection.setSelectedTrip(null);
                                tripSection.setSelection(selection);
                                vagonSelection.setListVagons(new ArrayList<VagonVO>());
                                tripVagonSection.setSelection(vagonSelection);
                            } catch (Exception e) {
                                logger.error(e.getMessage(), e);
                                ErrorDialog dialog = new ErrorDialog(getSite().getShell(), Activator.getMessage("common.dialog.error.title"), e.getMessage(), new Status(1, "edytor", e.getMessage()), 1);
                                dialog.open();
                            }
                        } else {
                            compositionSelection.setSelectedComposition(null);
                        }
                        updateButtons();
                    }
                });
            }
        });
        tripSection.addSelectionListener(new ISelectionListener<TripSelection>() {
            @Override
            public void selectionChanged(final TripSelection selection) {
                BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
                    @Override
                    public void run() {
                        if (selection.getSelectedTrip() != null) {
                            vagonSelection.setListVagons(selection.getSelectedTrip().getListVagons());
                            tripVagonSection.setSelection(vagonSelection);
                        }
                        updateButtons();
                    }
                });
            }
        });

        compositionSection.setSelection(compositionSelection);
        tripSection.setSelection(selection);
    }

    @Override
    protected void doSave() throws Exception {
    }

    @Override
    protected void doCancel() throws Exception {
        selection = initSelection();
        compositionSection.setSelection(compositionSelection);
        updateSelection();
    }

    @Override
    protected TripSelection initSelection() throws Exception {
        compositionSelection = new CompositionSelection();
        vagonSelection = new VagonSelection();

        ICompositionService compositionService = ServiceManager.getInstance().getCompositionService();
        List<CompositionVO> listAllCompositions = compositionService.getListAllCompositions();
        compositionSelection.setListAllCompositions(listAllCompositions);
        compositionSelection.setEditorState(EditorStateSL.CLEAN);

        Map<CompositionVO, List<VagonVO>> mapRelation = new LinkedHashMap<CompositionVO, List<VagonVO>>();
        for (CompositionVO composition : listAllCompositions) {
            mapRelation.putAll(compositionService.getCompositionVagonRelation(composition));
        }
        vagonSelection.setEditorState(EditorStateSL.CLEAN);
        vagonSelection.setMapCompositionVagons(mapRelation);

        IStationService stationService = ServiceManager.getInstance().getStationService();
        List<StationVO> listAllStations = stationService.getAllStations();
        Map<StationVO, Map<StationVO, Double>> mapDistances = new HashMap<StationVO, Map<StationVO, Double>>();
        for (StationVO stationVO : listAllStations) {
            Map<StationVO, Double> distanceMap = stationService.getDistanceMap(stationVO);
            mapDistances.put(stationVO, distanceMap);
        }

        TripSelection tripSelection = new TripSelection();
        tripSelection.setListComposition(listAllCompositions);
        tripSelection.setListStation(listAllStations);
        tripSelection.setMapDistances(mapDistances);
        tripSelection.setListTrips(new ArrayList<TripVO>());
        return tripSelection;
    }

    private void updateSelection() throws Exception {
        ITripService tripService = ServiceManager.getInstance().getTripService();
        if (compositionSelection.getSelectedComposition() != null) {
            selection.setListTrips(tripService.getTripsForComposition(compositionSelection.getSelectedComposition().getId()));
            if (selection.getSelectedTrip() != null) {
                selection.setSelectedTrip(tripService.getTrip(selection.getSelectedTrip().getId()));
                vagonSelection.setListVagons(selection.getSelectedTrip().getListVagons());
            } else {
                vagonSelection.setListVagons(new ArrayList<VagonVO>());
            }
        } else {
            selection.setListTrips(new ArrayList<TripVO>());
            selection.setSelectedTrip(null);
            vagonSelection.setListVagons(new ArrayList<VagonVO>());
        }
        tripSection.setSelection(selection);
        tripVagonSection.setSelection(vagonSelection);
        updateButtons();
    }

    @Override
    public void setFocus() {
        setDirty(true);
        editorCancelAction.run();
    }

    private void updateButtons() {
        editorNewAction.setEnabled(compositionSelection.getSelectedComposition() != null);
        editorEditAction.setEnabled(selection.getSelectedTrip() != null);
        editorDeleteAction.setEnabled(selection.getSelectedTrip() != null);
    }

}
